#!/bin/bash

# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # 无颜色

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

log_step() {
    echo -e "${BLUE}[STEP]${NC} $1"
}

# 检查是否为root用户
if [ "$(id -u)" != "0" ]; then
   log_error "此脚本必须以root权限运行" 
   exit 1
fi

# 设置环境变量
APP_DIR="/var/www/box-admin"
BACKUP_DIR="/var/backups/box-admin/$(date +%Y%m%d_%H%M%S)"
LOG_FILE="/var/log/box-admin/deploy_$(date +%Y%m%d_%H%M%S).log"
DEPLOY_LOCK="/tmp/box_admin_deploy.lock"

# 确保日志目录存在
mkdir -p "$(dirname "$LOG_FILE")"
mkdir -p "$BACKUP_DIR"

# 将所有输出重定向到日志文件
exec > >(tee -a "$LOG_FILE") 2>&1

# 显示脚本横幅
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "  妙趣拾光锦盒管理系统 - 自动化部署工具 v2.0"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

# 检查部署锁，防止多个部署脚本同时运行
if [ -f "$DEPLOY_LOCK" ]; then
    LOCK_PID=$(cat "$DEPLOY_LOCK")
    if ps -p "$LOCK_PID" > /dev/null; then
        log_error "另一个部署进程 (PID: $LOCK_PID) 正在运行。如果确定没有其他部署进程在运行，请删除锁文件: $DEPLOY_LOCK"
        exit 1
    else
        log_warn "发现过时的部署锁，将继续执行"
        rm -f "$DEPLOY_LOCK"
    fi
fi

# 创建部署锁
echo $$ > "$DEPLOY_LOCK"

# 定义清理函数，确保脚本结束后删除锁文件
cleanup() {
    rm -f "$DEPLOY_LOCK"
    log_info "部署完成，锁文件已删除"
}

# 捕获退出信号，确保锁文件被删除
trap cleanup EXIT

log_step "开始自动化部署流程..."
log_info "应用目录: $APP_DIR"
log_info "备份目录: $BACKUP_DIR"
log_info "日志文件: $LOG_FILE"
log_info "部署时间: $(date)"

# 检查应用目录是否存在
if [ ! -d "$APP_DIR" ]; then
    log_error "应用目录 $APP_DIR 不存在！请先运行初始部署脚本。"
    exit 1
fi

# 创建数据库备份
log_step "创建数据库备份..."
if [ -f "$APP_DIR/scripts/backup_db.py" ]; then
    cd "$APP_DIR"
    source venv/bin/activate
    python scripts/backup_db.py
    
    if [ $? -eq 0 ]; then
        log_info "数据库备份成功"
    else
        log_warn "数据库备份失败，但将继续部署过程"
    fi
    deactivate
else
    log_warn "数据库备份脚本不存在，跳过数据库备份"
fi

# 创建文件备份
log_step "创建应用文件备份..."
rsync -a --exclude="venv" --exclude=".git" --exclude="node_modules" "$APP_DIR/" "$BACKUP_DIR/"
log_info "备份已保存到: $BACKUP_DIR"

# 进入应用目录
cd "$APP_DIR" || {
    log_error "无法进入应用目录！"
    exit 1
}

# 获取部署前的Git版本
OLD_VERSION=$(git describe --always --tags 2>/dev/null || echo 'Unknown')
log_info "当前版本: $OLD_VERSION"

# 检查是否是Git仓库
if [ ! -d ".git" ]; then
    log_warn "目录不是Git仓库，跳过代码更新步骤"
else
    # 保存当前分支名
    CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
    log_info "当前分支: $CURRENT_BRANCH"

    # 提示用户选择更新方式
    echo ""
    echo "选择更新方式:"
    echo "  [1] 从当前分支 ($CURRENT_BRANCH) 拉取最新代码"
    echo "  [2] 切换到指定分支/标签"
    echo "  [3] 跳过代码更新"
    read -p "请选择 (默认: 1): " UPDATE_CHOICE
    UPDATE_CHOICE=${UPDATE_CHOICE:-1}

    case $UPDATE_CHOICE in
        1)
            # 拉取最新代码
            log_step "从当前分支 $CURRENT_BRANCH 拉取最新代码..."
            
            # 检查本地变更
            if [ -n "$(git status --porcelain)" ]; then
                log_warn "本地有未提交的变更，这些变更将被覆盖"
                git status --porcelain
                read -p "是否继续? (y/n, 默认: n): " CONTINUE_WITH_CHANGES
                if [ "${CONTINUE_WITH_CHANGES,,}" != "y" ]; then
                    log_error "部署已取消"
                    exit 1
                fi
            fi
            
            # 保存最新提交前的版本
            OLD_COMMIT=$(git rev-parse HEAD)
            
            # 获取远程变更
            git fetch --all
            
            # 检查是否有新的提交
            NEW_COMMIT=$(git rev-parse origin/$CURRENT_BRANCH)
            if [ "$OLD_COMMIT" = "$NEW_COMMIT" ]; then
                log_info "已经是最新版本，无需更新代码"
            else
                # 显示即将应用的变更摘要
                log_info "即将应用以下变更:"
                git log --oneline --no-decorate $OLD_COMMIT..$NEW_COMMIT
                
                # 应用变更
                git reset --hard origin/"$CURRENT_BRANCH"
                git pull
                log_info "代码已更新到最新版本"
            fi
            ;;
        2)
            # 切换到指定分支/标签
            echo ""
            echo "可用的分支:"
            git branch -r | grep -v HEAD | sed 's/origin\//  /'
            echo ""
            echo "可用的标签:"
            git tag | sed 's/^/  /'
            echo ""
            read -p "输入要切换到的分支或标签名: " TARGET_BRANCH
            
            if [ -z "$TARGET_BRANCH" ]; then
                log_error "未提供有效的分支或标签名，部署已取消"
                exit 1
            fi
            
            log_step "切换到 $TARGET_BRANCH..."
            git fetch --all --tags
            
            # 检查分支/标签是否存在
            if git rev-parse --verify --quiet origin/"$TARGET_BRANCH" >/dev/null; then
                # 分支存在
                git checkout "$TARGET_BRANCH"
                git reset --hard origin/"$TARGET_BRANCH"
            elif git rev-parse --verify --quiet "$TARGET_BRANCH" >/dev/null; then
                # 标签存在
                git checkout "$TARGET_BRANCH"
            else
                log_error "分支或标签 '$TARGET_BRANCH' 不存在，部署已取消"
                exit 1
            fi
            ;;
        3)
            log_info "跳过代码更新"
            ;;
        *)
            log_warn "无效选择，使用默认选项: 从当前分支拉取"
            git fetch --all
            git reset --hard origin/"$CURRENT_BRANCH"
            git pull
            ;;
    esac
fi

# 获取部署后的Git版本
NEW_VERSION=$(git describe --always --tags 2>/dev/null || echo 'Unknown')
if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
    log_info "版本已更新: $OLD_VERSION → $NEW_VERSION"
fi

# 更新Node.js环境（针对前端项目）
log_step "检查Node.js环境..."
if ! command -v node &> /dev/null; then
    log_error "Node.js未安装，请先安装Node.js和npm！"
    exit 1
fi

NODE_VERSION=$(node -v)
NPM_VERSION=$(npm -v)
log_info "Node.js版本: $NODE_VERSION"
log_info "npm版本: $NPM_VERSION"

# 检查package.json是否存在
if [ ! -f "package.json" ]; then
    log_error "package.json不存在，可能不是有效的前端项目！"
    exit 1
fi

# 更新前端依赖
log_step "安装/更新前端依赖..."
if [ -f "yarn.lock" ]; then
    # 使用yarn
    if ! command -v yarn &> /dev/null; then
        log_info "安装yarn包管理器..."
        npm install -g yarn
    fi
    yarn install --frozen-lockfile
    INSTALL_RESULT=$?
else
    # 使用npm
    npm ci
    INSTALL_RESULT=$?
fi

if [ $INSTALL_RESULT -ne 0 ]; then
    log_warn "依赖安装可能存在问题，尝试使用常规安装方式..."
    if [ -f "yarn.lock" ]; then
        yarn install
    else
        npm install
    fi
fi

# 检查.env文件并配置
log_step "检查环境配置..."
ENV_FILE=".env.production"
if [ ! -f "$ENV_FILE" ]; then
    log_warn "生产环境配置文件不存在，创建默认配置..."
    cat > "$ENV_FILE" << EOF
# 生产环境配置
VITE_API_BASE_URL=http://106.15.51.42:8000/api
VITE_ENVIRONMENT=production
VITE_UPLOADS_URL=http://106.15.51.42:8000/uploads
VITE_SITE_TITLE=妙趣拾光锦盒管理系统
EOF
    log_info "环境配置文件已创建"
else
    # 检查API基本URL配置
    if ! grep -q "VITE_API_BASE_URL=" "$ENV_FILE"; then
        echo "VITE_API_BASE_URL=http://106.15.51.42:8000/api" >> "$ENV_FILE"
        log_info "添加了API基本URL配置"
    fi
    
    # 检查环境设置
    if ! grep -q "VITE_ENVIRONMENT=production" "$ENV_FILE"; then
        echo "VITE_ENVIRONMENT=production" >> "$ENV_FILE"
        log_info "添加了环境设置配置"
    fi
    
    log_info "环境配置已验证"
fi

# 构建前端项目
log_step "构建前端项目..."
# 查看package.json中的构建命令
BUILD_COMMAND=$(grep -o '"build:prod":[^,]*' package.json 2>/dev/null || 
                grep -o '"build:production":[^,]*' package.json 2>/dev/null || 
                grep -o '"build":[^,]*' package.json)

if [ -z "$BUILD_COMMAND" ]; then
    log_warn "未找到标准构建命令，使用默认npm run build"
    npm run build
else
    # 提取实际的构建命令
    if [[ $BUILD_COMMAND == *"build:prod"* ]]; then
        log_info "使用生产环境构建命令: npm run build:prod"
        npm run build:prod
    elif [[ $BUILD_COMMAND == *"build:production"* ]]; then
        log_info "使用生产环境构建命令: npm run build:production"
        npm run build:production
    else
        log_info "使用标准构建命令: npm run build"
        npm run build
    fi
fi

# 检查构建结果
if [ ! -d "dist" ] && [ ! -d "build" ]; then
    log_error "构建失败！未找到dist或build目录。"
    
    # 查看构建日志
    if [ -f "npm-debug.log" ]; then
        log_info "npm构建日志:"
        tail -n 50 npm-debug.log
    fi
    
    # 提示是否回滚
    read -p "是否回滚到之前的版本? (y/n, 默认: y): " ROLLBACK
    if [ "${ROLLBACK,,}" != "n" ]; then
        log_step "正在回滚到之前的版本..."
        rsync -a "$BACKUP_DIR/" "$APP_DIR/"
        log_info "已回滚到之前的版本"
    else
        log_warn "用户选择不回滚，但构建可能存在问题"
    fi
else
    BUILD_DIR="dist"
    if [ ! -d "dist" ] && [ -d "build" ]; then
        BUILD_DIR="build"
    fi
    
    log_info "构建成功！输出目录: $BUILD_DIR"
    
    # 检查构建目录中是否存在index.html
    if [ ! -f "$BUILD_DIR/index.html" ]; then
        log_warn "构建目录中未找到index.html，构建可能不完整"
    else
        log_info "构建验证成功"
    fi
fi

# 配置Nginx（如果需要）
log_step "检查Nginx配置..."
NGINX_CONF="/etc/nginx/conf.d/box-admin.conf"
NGINX_ENABLED="/etc/nginx/sites-enabled/box-admin.conf" # 如果使用Debian/Ubuntu

if [ ! -f "$NGINX_CONF" ]; then
    log_info "创建Nginx配置文件..."
    cat > "$NGINX_CONF" << 'EOF'
server {
    listen 80;
    server_name admin.boxapp.cn;
    root /var/www/box-admin/dist;
    index index.html;

    # 日志配置
    access_log /var/log/nginx/box-admin-access.log;
    error_log /var/log/nginx/box-admin-error.log;

    # 处理前端路由
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 缓存静态资源
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires max;
        add_header Cache-Control "public, max-age=31536000";
    }

    # 安全相关头信息
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Frame-Options SAMEORIGIN;
    add_header Referrer-Policy strict-origin-when-cross-origin;
}
EOF
    
    # 如果是Debian/Ubuntu系统，创建符号链接到sites-enabled
    if [ -d "/etc/nginx/sites-enabled" ]; then
        if [ ! -f "$NGINX_ENABLED" ]; then
            ln -s "$NGINX_CONF" "$NGINX_ENABLED"
            log_info "已创建Nginx站点启用链接"
        fi
    fi
    
    log_info "Nginx配置文件已创建"
    
    # 检查Nginx配置是否有效
    if nginx -t; then
        log_info "Nginx配置检查通过"
    else
        log_error "Nginx配置无效，请手动检查!"
    fi
else
    log_info "Nginx配置文件已存在"
    
    # 检查Nginx配置是否有效
    if nginx -t; then
        log_info "Nginx配置检查通过"
    else
        log_warn "Nginx配置可能存在问题，请手动检查"
    fi
fi

# 重新加载Nginx
log_step "重新加载Nginx配置..."
systemctl reload nginx
NGINX_RELOAD_RESULT=$?

if [ $NGINX_RELOAD_RESULT -eq 0 ]; then
    log_info "Nginx配置已成功重新加载"
else
    log_error "Nginx重新加载失败！请检查Nginx状态"
    systemctl status nginx
fi

# 测试应用可访问性
log_step "测试应用可访问性..."
if curl -s --head http://localhost | grep "200 OK" > /dev/null; then
    log_info "应用可通过本地访问"
else
    log_warn "无法通过本地访问应用，可能需要进一步配置"
fi

# 清理旧备份（保留最近10个备份）
log_step "管理备份文件..."
BACKUP_COUNT=$(find /var/backups/box-admin -maxdepth 1 -type d | wc -l)
if [ $BACKUP_COUNT -gt 11 ]; then  # 11因为包括父目录
    log_info "清理旧备份，只保留最近10个备份..."
    ls -dt /var/backups/box-admin/20* | tail -n +11 | xargs rm -rf
    log_info "旧备份清理完成"
fi

log_step "部署过程完成!"
log_info "部署日志保存在: $LOG_FILE"

# 显示部署摘要
echo ""
log_info "============= 部署摘要 ============="
log_info "部署时间: $(date)"
if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then
    log_info "代码版本: $OLD_VERSION → $NEW_VERSION"
else
    log_info "代码版本: $NEW_VERSION (未变更)"
fi
log_info "应用URL: http://admin.boxapp.cn"
nginx_status=$(systemctl status nginx | grep "Active:")
log_info "Nginx状态: $nginx_status"
log_info "=====================================" 